package com.demo.services.impl;

import com.demo.common.AppResult;
import com.demo.common.ResultCode;
import com.demo.dao.UserMapper;
import com.demo.exception.ApplicationException;
import com.demo.model.User;
import com.demo.services.IUserService;
import com.demo.utils.MD5Utils;
import com.demo.utils.StringUtils;
import com.demo.utils.UUIDUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @Author quan
 * @Description 4-实现Service接口
 * @Date 2023/8/10 9:45
 */

@Slf4j
@Service
public class UserServiceImpl implements IUserService {
    @Resource
    private UserMapper userMapper;
    /**
     * 根据用户名查询用户信息（注册功能）
     * @param username 用户名
     * @return 用户
     */
    @Override
    public User selectByName(String username) {
        //1、在实现过程中，要对每一个必传参数做非空和有效性校验。
        if(StringUtils.isEmpty(username)){
            //打印日志：参数异常
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2、根据用户名查询用户信息
        User user = userMapper.selectByName(username);
        //3、返回结果
        return user;
    }

    /**
     * 创建普通用户：插入用户信息在数据库
     * @param user 用户信息
     */
    @Override
    public void createNormalUser(User user) {
        //1、对必传参数做非空校验
        if(user == null || StringUtils.isEmpty(user.getUsername())
        || StringUtils.isEmpty(user.getPassword())
        || StringUtils.isEmpty(user.getNickname())
        || StringUtils.isEmpty(user.getSalt())){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2、校验用户名是否存在：不存在的话才注册成功；存在的话报异常：用户名已存在
        User existUser = selectByName(user.getUsername());
        if(existUser!=null){
            //打印日志
            log.warn(ResultCode.FAILED_USER_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }
        //3、为有默认值的属性 设置默认值（就是创建的数据库表中的默认自端，在这里都要写）
        //设置性别：默认2保密
        if(user.getGender()!=null){
            if(user.getGender()<0 || user.getGender()>2){
                //设置默认值为2：保密类型
                user.setGender((byte) 2);
            }
        }else{
            user.setGender((byte) 2);
        }
        //设置发帖数：默认0
        user.setArticleCount(0);
        //设置是否为管理员：默认0 普通用户
        user.setIsAdmin(0);
        //设置状态：默认0正常
        user.setState((byte) 0);
        //设置删除状态：默认0 否
        user.setDeleteState((byte) 0);
        //设置时间
        Date date = new Date();
        user.setCreateTime(date); //创建时间
        user.setUpdateTime(date); //删除时间
        //除了必传参数，有默认值参数、时间之外，其他参数可填可不填，所以使用动态sql
        //4、写入数据库
        int row = userMapper.insertSelective(user);
        //5、判断结果
        if(row!=1){
            //说明写入数据失败，打印日志
            log.warn(ResultCode.FAILED_CREATE.toString()+"注册用户失败! username="+user.getUsername());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
    }

    /**
     * 用户登录
     * @param username 传入参数：用户名
     * @param password 传入参数：密码
     * @return 用户对象
     */
    @Override
    public User login(String username, String password){
        //1、对参数做非空校验
        if(StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2、根据用户名查询用户信息
        User user = selectByName(username);
        //做非空校验
        if(user == null){
            //打印日志：用户不存在
            log.info(ResultCode.FAILED_NOT_EXISTS.toString()+",username="+username);
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //3、校验密码是否正确
        //密码的校验方式：从数据库中获取到盐，对输入的密码加盐后的结果与直接从数据库中查询出来的password进行比较：相等则登录成功，否则失败。
        //获取盐
        String salt = user.getSalt();
        //对输入的密码加盐
        String saltPassword = MD5Utils.md5Salt(password, salt);
        //判断
        if(!saltPassword.equalsIgnoreCase(user.getPassword())){
            //说明密码不正确
            //打印日志
            log.info("密码输入错误，username="+username+",password="+password);
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //密码正确，返回用户。
        return user;
    }

    /**
     * 根据用户Id查询用户信息
     * @param id 用户Id
     * @return User
     */
    @Override
    public User selectById(Long id) {
        //1、对Id做非空校验
        if(id == null || id <0){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2、通过调用mapper查询用户信息
        User user = userMapper.selectByPrimaryKey(id);
        //3、返回user对象
        return user;
    }

    /**
     * 更新帖子数量
     * @param id 要更新的用户Id
     */
    @Override
    public void addOneArticleCountById(Long id) {
        //1-参数校验
        if(id == null || id<=0){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2-通过id查询现有用户的信息
        User user = selectById(id);
        //3-校验用户是否为空
        if(user == null){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //4-构造要更新的对象
        User updateUser = new User();
        updateUser.setId(user.getId()); //设置用户Id
        updateUser.setArticleCount(user.getArticleCount()+1); //设置帖子数+1
        updateUser.setUpdateTime(new Date());//设置更新时间
        //5-调用dao,选择性更新用户信息
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //6-判断结果
        if(row != 1){
            //打印日志
            log.warn(ResultCode.ERROR_SERVICES.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }

    @Override
    public void subOneArticleCountById(Long id) {
        //1-参数校验
        if(id == null || id<=0){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2-通过id查询现有用户的信息
        User user = selectById(id);
        //3-校验用户是否为空
        if(user == null){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //4-构造要更新的对象
        User updateUser = new User();
        updateUser.setId(user.getId()); //设置用户Id
        updateUser.setArticleCount(user.getArticleCount()-1); //设置帖子数+1
        updateUser.setUpdateTime(new Date());//设置更新时间
        //5-调用dao,选择性更新用户信息
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //6-判断结果
        if(row != 1){
            //打印日志
            log.warn(ResultCode.ERROR_SERVICES.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }

    @Override
    public void modifyInfo(User user) {
        //1-非空校验:对user对象做
        if(user == null){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //校验user是否存在
        User existUser = selectById(user.getId());
        if(existUser == null || existUser.getDeleteState()==1){
            //用户不存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //2-定义要更新的对象
        User updateUser = new User();
        //设置用户Id
        updateUser.setId(user.getId());
        //3-这6个参数是选填的，在赋值的过程中做非空校验
        //3-0 定义标志位
        boolean checkParam = false;
        //3-1 用户名
        if(!StringUtils.isEmpty(user.getUsername())){
            //更新用户名，这个用户名是要判断是不是唯一的，不是的话抛异常
            //根据当前用户名查询用户是否存在
            User checkUser = selectByName(user.getUsername());
            //用户已经存在
            if(checkUser !=null){
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            //用户名不存在，就修改用户名
            updateUser.setUsername(user.getUsername());
            //更新标识
            checkParam = true;
        }
        //3-2 昵称
        if(!StringUtils.isEmpty(user.getNickname())){
            //设置昵称
            updateUser.setNickname(user.getNickname());
            //设置标志位
            checkParam = true;
        }
        //3-3 性别
        if(user.getGender()!=null){
            //设置性别
            //0女 1男 2保密
            updateUser.setGender(user.getGender());
            //校验有效性，在0和2之外的设置默认为2
            if(updateUser.getGender()<0 || updateUser.getGender()>2){
                //设置默认值2
                updateUser.setGender((byte) 2);
            }
            //设置标志位
            checkParam = true;
        }
        //3-4 邮箱
        if(!StringUtils.isEmpty(user.getEmail())){
            //设置昵称
            updateUser.setEmail(user.getEmail());
            //设置标志位
            checkParam = true;
        }
        //3-5 电话号码
        if(!StringUtils.isEmpty(user.getPhoneNumber())){
            //设置昵称
            updateUser.setPhoneNumber(user.getPhoneNumber());
            //设置标志位
            checkParam = true;
        }
        //3-6 设置个人简介
        if(!StringUtils.isEmpty(user.getRemark())){
            //设置昵称
            updateUser.setRemark(user.getRemark());
            //设置标志位
            checkParam = true;
        }
        //4-检查标识是否通过
        if(checkParam == false){
            //没有校验通过
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS)+"所有参数不能同时为空");
        }
        //5-调用mapper
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
//        log.info(row+"11111111");
        //6-校验row
        if(row != 1){
            //打印日志
            log.warn(ResultCode.ERROR_SERVICES.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }

    @Override
    public void modifyPassword(Long id, String oldPassword, String newPassword) {
        //1-非空校验
        if(id == null || id<=0 || StringUtils.isEmpty(newPassword) || StringUtils.isEmpty(oldPassword)){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2-根据用户id查询用户判断用户是否存在
        User user = selectById(id);
        if(user == null || user.getDeleteState() == 1){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //3-校验老密码是否正确
        //3-1 先获取数据库中的盐
        String db_salt = user.getSalt();
        //3-2 对旧密码加盐获取密文
        String encryptOldPassword = MD5Utils.md5Salt(oldPassword,db_salt);
        //3-3 判断加盐后的旧密码与数据库中的密码是否相等:判断的时候忽略大小写
        if(!encryptOldPassword.equals(user.getPassword())){
            //不相等，给出提示
            //抛出异常：密码校验失败
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME)+"old password" + oldPassword+",user id=" + id);
        }
        //4-校验通过，生成新密码
        //4-1 生成新盐
        String salt = UUIDUtils.UUID_32();
        //4-2 生成新密码的密文
        String encryptPassword = MD5Utils.md5Salt(newPassword,salt);
        //5-构造更新对象
        User updateUser = new User();
        updateUser.setId(id);//用户Id
        updateUser.setPassword(encryptPassword); //密码
        updateUser.setSalt(salt); //盐
        updateUser.setUpdateTime(new Date()); //更新时间
        //6-调用mapper
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //7-校验row
        if(row!=1){
            //打印日志
            log.warn(ResultCode.ERROR_SERVICES.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }
}
